package Server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.ArrayList;

import Requete.Requete;
import Requete.RequeteAjoutPersonne;
import Requete.RequeteAjoutSurnomAPersonne;
import Requete.RequeteListerSurnomDunePersonne;
import Requete.RequeteListerToutesPersonnes;
import Requete.RequeteModifierPersonne;
import Requete.RequeteQuitter;
import Requete.RequeteSupprimerPersonne;
import Requete.RequeteSupprimerSurnomDunePersonne;


import util.Personne;

/**
 * classe qui represente un thread qui s'occupe d'un seul client
 * @author Graoudi Nohri & Ochi Ghazi
 *
 */
public class MonThread extends Thread {
	private Socket             soc;
	private ObjectOutputStream out;
	private ObjectInputStream   in;
	
	private ArrayList<Personne> listDePersonne;
	
	/**
	 *  Teste si une donn�e de la personne (nom,prenom,age et surnoms) ne sont pas nulle
	 * @param p la personne � tester
	 * @return si la personne ne contient aucune donn�es null
	 */
	static private boolean isNull(Personne p){
		if( p                 == null || 
		    p.getNom     ()   == null ||
		    p.getSurnoms ()   == null) return true;
		
		for(int i = 0 ;i < p.getSurnoms().size();++i){
			if (p.getSurnoms().get(i) == null) return true;
		}
		return false;
	}
	/**
	 * 
	 * @param soc le scoket pour comuniquer avec le client
	 * @param listDePersonne la base de donn�es
	 */
	public MonThread(Socket soc, ArrayList<Personne> listDePersonne) {
        this.soc = soc;
        this.listDePersonne = listDePersonne;
    }
	/**
	 * fonction appeler par la m�thode start() de Thread	
	 */
	 public  void run(){
			try {
				launch();
			} catch (IOException e) {
				e.printStackTrace();
			}	
	 }
	 
	 /**
	  * boucle qui traite toutes les demandes du client jusqu'a sa d�connexion 
	  */
	  public void launch() throws IOException{
	
	    	System.out.println("Client connect� : "+soc.toString());
			try{out = new ObjectOutputStream(soc.getOutputStream());}
			catch (IOException e){
				System.out.println("erreur ouverture output vers client");
				return;
			}
			try{in = new ObjectInputStream(soc.getInputStream());}
			catch (IOException e){
				System.out.println("erreur ouverture input vers client");
				return;
			}
			for(;;){
				Requete r;
				System.out.println("En attente d'une requete : "+listDePersonne.size());
				try {
					r = (Requete) in.readObject();
				} catch (IOException e) {
					System.out.println("Impossible de lire un objet: " +e.getMessage());
					return;
				} catch (ClassNotFoundException e) {
					System.out.println("Objet reçu de type inconnue : "+ e.getMessage());
					continue;
				}
					if (r instanceof RequeteAjoutPersonne){
						System.out.println("Ajout d'une personne");
						AjoutPersonne((RequeteAjoutPersonne)r);
					}
					else if (r instanceof RequeteAjoutSurnomAPersonne){
						System.out.println("Ajout d'un surnom à une personne");
						AjoutSurnomAPersonne((RequeteAjoutSurnomAPersonne)r);
					}
					else if (r instanceof RequeteQuitter){
						System.out.println("le client se déconnecte");
						in.close();
						out.close();
						launch();
					}
					else if (r instanceof RequeteModifierPersonne){
						System.out.println("Modification d'une personne");
						ModifierPersonne((RequeteModifierPersonne)r);
					}
					else if (r instanceof RequeteSupprimerPersonne){
						System.out.println("Supression d'une personne");
						SupprimerPersonne((RequeteSupprimerPersonne)r);
					}
					else if (r instanceof RequeteListerToutesPersonnes){
						ListerToutesPersonnes();
					}
					else if(r instanceof RequeteSupprimerSurnomDunePersonne){
						SupprimerSurnomPersonne((RequeteSupprimerSurnomDunePersonne)r);
					}
					else if (r instanceof RequeteListerSurnomDunePersonne){
						ListerSurnomDunePersonne((RequeteListerSurnomDunePersonne)r);
					}
					
			}
		}
  /**
   * fonction  appeler si le client d�sire connaitre toutes les personnes
   */
	private void ListerToutesPersonnes(){

		try {
			out.writeObject(listDePersonne);
			out.reset();
			
			System.out.println("Envoie de la liste des personnes");
		} catch (IOException e) {
			System.out.println("Impossible d'envoyer la liste de personne : "+e.getMessage());
		}
	}
	/**
	 * fonction  appeler si le client désire ajouter une personne 
	 * @param r la requeter envoyé par le client
	 * @throws IOException
	 */
	private void AjoutPersonne(RequeteAjoutPersonne r) throws IOException{
		if(isNull(r.getPersonne())){
			out.writeBoolean(false);
			out.flush();
			return;
		}
		for (int i = 0 ; i <listDePersonne.size();++i)
			if (listDePersonne.get(i).equals(r.getPersonne())){
				out.writeObject("Erreur 05 : Cette personne existe déjà");
				out.flush();
				return;
			}
		
		listDePersonne.add(r.getPersonne());
		System.out.println("Ajout de la personne "+r.getPersonne());
		out.writeObject("OK");
		out.flush();
		out.flush();
	}
	/**
	 * fonction  appeler si le clien d�sire modifier une personnes
	 * @param r la requeter envoy� par le client
	 * @throws IOException
	 */
	private void ModifierPersonne(RequeteModifierPersonne r) throws IOException{
		if(isNull(r.getNew())|| isNull(r.getOld()) ){
			out.writeBoolean(false);
			out.flush();
			return;
		}
		boolean existe = false;
		int i = 0;
		for (; i < listDePersonne.size();++i)
		{ 
			if(listDePersonne.get(i).equals(r.getOld())){existe = true;break;}
		}
		if(!existe)
			out.writeBoolean(false);
		else{
			String surnomComun = r.getOld().getSurnoms().get(0);
			ArrayList<String> surnoms = listDePersonne.get(i).getSurnoms();
			for(int j = 0; j<surnoms.size();j++){
				if(!(surnoms.get(j).equals(surnomComun))){
				r.getNew().getSurnoms().add(surnoms.get(j));}
			}
			listDePersonne.set(i, r.getNew());
			out.writeBoolean(true);
		}
		out.flush();
		
	}
	/**
	 * fonction  appeler si le client d�sire supprimer  une personne
	 * @param r la requeter envoy� par le client
	 * @throws IOException
	 */
	private void SupprimerPersonne(RequeteSupprimerPersonne r) throws IOException{
		if(isNull(r.getPesonne())){
			out.writeBoolean(false);
			out.flush();
			return;
		}
		boolean existe = false;
		int i = 0;
		for (; i < listDePersonne.size();++i)
		{ 
			if(listDePersonne.get(i).equals(r.getPesonne())){existe = true;break;}
		}
		if(!existe){
			out.writeBoolean(false);
		}
		else{
			listDePersonne.remove(i);
			out.writeBoolean(true);
		}
		out.flush();
	}
	/**
	 * fonction  appeler si le client d�sire supprimer le surnom d'une personne
	 * @param r la requeter envoy� par le client
	 * @throws IOException
	 */
	private void SupprimerSurnomPersonne(RequeteSupprimerSurnomDunePersonne r) {
		if(isNull(r.getPersonne()) || r.getSurnom() == null){
			try {
				out.writeObject(4);
				out.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			return;
		}
		
		int i = 0;
		boolean existe = false;
		for (; i < listDePersonne.size();++i)
		{ 
			if (listDePersonne.get(i).equals(r.getPersonne())){
				existe=true;
				break;
			}
		}
		if(!existe){
			try {
				out.writeObject(4);
				out.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			return;
		}
		
		ArrayList<String> surnoms = listDePersonne.get(i).getSurnoms();
		if (surnoms.size() < 2){
			try {
				out.writeObject(7);
				out.flush();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			return;
		}
		else{
			for (int j = 0; j <surnoms.size();++j){
				if(surnoms.get(j).equals(r.getSurnom())){
					surnoms.remove(j);
					try {
						out.writeObject(10);
						out.flush();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					
					return;
				}
			}	
		}
		
	}
	/**
	 * fonction  appeler si le client d�sire lister les surnomes d'une personnes 
	 * @param r la requeter envoy� par le client
	 * @throws IOException
	 */
	private void ListerSurnomDunePersonne(RequeteListerSurnomDunePersonne r) {
		if(isNull(r.getPersonne())){
			try {
				out.writeObject(new ArrayList<String>());
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		for(int i = 0; i  <listDePersonne.size();++i){
			if(listDePersonne.get(i).equals(r.getPersonne())){
				try {
					out.writeObject(listDePersonne.get(i).getSurnoms());
					out.reset();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				return;
			}
		}	
		ArrayList<String> erreur = new ArrayList<String>();
			if(listDePersonne.size()==0){
				erreur.add("Erreur 03 : La base de données est vide");
				try {
					out.writeObject(erreur);
					out.reset();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return;
			}
			else{
				erreur.add("Erreur 04 : Cette personne n'existe pas");
				try {
					out.writeObject(erreur);
					out.reset();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				return;
			}
	}
	/**
	 * fonction  appeler si le client d�sire ajouter un surnom � une personnes
	 * @param r la requeter envoy� par le client
	 * @throws IOException
	 */
	private void AjoutSurnomAPersonne(RequeteAjoutSurnomAPersonne r) throws IOException{
		if(isNull(r.getPersonne()) || r.getSurnom() ==null){
			out.writeBoolean(false);
			out.flush();
			return;
		}
		
		// on verifie que le surnom n'a pas �t� attribu�
		for (int i = 0; i < listDePersonne.size();++i)
		{ 
			ArrayList<String> surnoms = listDePersonne.get(i).getSurnoms();
			for (int j = 0; j < surnoms.size();++j)
			{
				if (surnoms.get(j).equals(r.getSurnom())){
					out.writeObject("Erreur 06: Ce surnom est déja utilisé");
					out.flush();
					return;
				}
			}
		}
		// on verifie si la personne existe et on lui attribue le surnoms 
		for (int i = 0; i < listDePersonne.size();++i)
		{ 
			if (listDePersonne.get(i).equals(r.getPersonne())){
				listDePersonne.get(i).getSurnoms().add(r.getSurnom());
				System.out.println("Ajout du surnom  "+r.getSurnom()+" � la personne :"
						            +listDePersonne.get(i));
				out.writeObject("OK");
				out.flush();
				return;
			}
		}
		out.writeObject("Erreur 04 : Cette personne n'existe pas");
		out.flush();
		return;
		
	}
}
